
/* Copyright (C) 2007 Richard Uhler
 * This file is part of Esiply.
 *
 * Esiply is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License, Version 2,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

%{
#include <assert.h>
#include <ctype.h>
//#include <gc_cpp.h>

#include "Boolean.h"
#include "Expression.h"
#include "Number.h"
#include "Null.h"
#include "Reference.h"
#include "RegularExpressionLiteral.h"
#include "Statement.h"
#include "String.h"
#include "parser_wrap.h"

%}

%option debug
%option noyywrap
%option noyyalloc noyyrealloc noyyfree

%x IN_COMMENT
%x EXPECT_REGEX

%%

<INITIAL>{

"break"                     return BREAK;
"case"                      return CASE;
"catch"                     return CATCH;
"continue"                  return CONTINUE;
"default"                   return DEFAULT;
"delete"                    return DELETE;
"do"                        return DO;
"else"                      return ELSE;
"false"                     {
    yylval.expression = Boolean::False;
    return LITERAL;
}

"finally"                   return FINALLY;
"for"                       return FOR;
"function"                  return FUNCTION;
"if"                        return IF;
"in"                        return IN;
"instanceof"                return INSTANCEOF;
"new"                       return NEW;
"null"                      {
    yylval.expression = Null::null;
    return LITERAL;
}

"return"                    return RETURN;
"switch"                    return SWITCH;
"this"                      return THIS;
"throw"                     return THROW;
"true"                      {
    yylval.expression = Boolean::True;
    return LITERAL;
}
"synchronized"				return SYNCHRONIZED;
"try"                       return TRY;
"typeof"                    return TYPEOF;
"var"                       return VAR;
"void"                      return VOID;
"while"                     return WHILE;
"with"                      return WITH;
"==="                       return SDEQ;
"!=="                       return SNEQ;
"||"                        return DBAR;
"&&"                        return DAMP;
">="                        return GTE;
"<="                        return LTE;
"=="                        return DEQ;
"!="                        return NEQ;
"++"                        return INC;
"--"                        return DEC;
"<<"                        return LEFT_SHIFT;
">>"                        return RIGHT_SHIFT;
">>>"                       return UNSIGNED_RIGHT_SHIFT;
"<<="                       {
    yylval.binop = &BinaryExpression::left_shift_assign;
    return ASSIGNMENT_OPERATOR;
}
">>="                       {
    yylval.binop = &BinaryExpression::right_shift_assign;
    return ASSIGNMENT_OPERATOR;
}
">>>="                      {
    yylval.binop = &BinaryExpression::unsigned_right_shift_assign;
    return ASSIGNMENT_OPERATOR;
}
"+="                        {
    yylval.binop = &BinaryExpression::add_assign;
    return ASSIGNMENT_OPERATOR;
}
"-="                        {
    yylval.binop = &BinaryExpression::subtract_assign;
    return ASSIGNMENT_OPERATOR;
}
"*="                        {
    yylval.binop = &BinaryExpression::multiply_assign;
    return ASSIGNMENT_OPERATOR;
}
"/="                        {
    yylval.binop = &BinaryExpression::divide_assign;
    return ASSIGNMENT_OPERATOR;
}
"%="                        {
    yylval.binop = &BinaryExpression::modulo_assign;
    return ASSIGNMENT_OPERATOR;
}
"&="                        {
    yylval.binop = &BinaryExpression::bitwise_and_assign;
    return ASSIGNMENT_OPERATOR;
}
"^="                        {
    yylval.binop = &BinaryExpression::bitwise_xor_assign;
    return ASSIGNMENT_OPERATOR;
}
"|="                        {
    yylval.binop = &BinaryExpression::bitwise_or_assign;
    return ASSIGNMENT_OPERATOR;
}

[a-zA-Z_$][a-zA-Z_$0-9]*    {   
    yylval.string = new String(yytext, yyleng);
    return IDENTIFIER;
}

\"([^\"]|\\\")*\"           {
    yylval.value = new String(yytext+1, yyleng-2);
    return LITERAL;
}

\'([^\']|\\\')*\'           {
    yylval.value = new String(yytext+1, yyleng-2);
    return LITERAL;
}

[0-9]+(\.[0-9]+)?(E|e(\+|-)?[0-9]*)?      {
    yylval.value = new Number(yytext, yyleng);
    return LITERAL;
}


"/*"                        BEGIN(IN_COMMENT);
"//".*$                     { }
[\n]                        { yylloc.last_line++; }
.                           { 
    if (!isspace(*yytext))
    {
        return *yytext;
    }
}

}       /* INITIAL */

<EXPECT_REGEX>[^*/\\\n][^/\\\n]*\/[gim]*  {
    BEGIN(INITIAL);
    // Find the '/' char to split between pattern and flags
    int i;
    for (i = 0; i < yyleng && yytext[i] != '/'; i++);
    String* pattern = new String(yytext, i);
    String* flags = new String(yytext+i+1, yyleng-(i+1));
    yylval.expression = new RegularExpressionLiteral(pattern, flags);
    return REGEX_LITERAL;
}

<IN_COMMENT>{
"*/"            BEGIN(INITIAL);
[^*\n]+         {}
"*"             {}
\n              { yylloc.last_line++; }
}


%%

void * yyalloc (size_t bytes)
{
    return malloc(bytes);
}

void * yyrealloc (void * ptr, size_t bytes)
{
    //return GC_REALLOC(ptr, bytes);
}

void yyfree (void * ptr) {      
    // Do nothing -- we leave it to the garbage collector.
}

void expect_regex()
{
    BEGIN(EXPECT_REGEX);
}

// vim: filetype=lex
